package com.beardedcoder.lowPower.service;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.IBinder;
import android.widget.RemoteViews;
import android.widget.Toast;

import com.beardedcoder.lowPower.R;
import com.beardedcoder.lowPower.activities.Launch;
import com.beardedcoder.lowPower.app.AppSettings;
import com.beardedcoder.lowPower.dao.BatteryDao;
import com.beardedcoder.lowPower.dao.DbLowPower;
import com.beardedcoder.lowPower.dao.impl.BatteryDaoImpl;
import com.beardedcoder.lowPower.model.BatteryData;
import com.beardedcoder.lowPower.model.BatteryDataFactory;
import com.beardedcoder.lowPower.model.TemporaryDataStorage;
import com.beardedcoder.utils.UtilBatteryInterpreter;
import com.beardedcoder.utils.db.DbToFileAdapter;

public class PowerService extends Service{
	public static final String INTENT_ACTION_LAST_UNPLUG_EVENT_STORE = "INTENT_ACTION_LAST_UNPLUG_EVENT_STORE";
	public static final String INTENT_ACTION_LAST_UNPLUG_EVENT_IGNORE = "INTENT_ACTION_LAST_UNPLUG_EVENT_IGNORE";
	public static final String INTENT_ACTION_DELETE_BATTERY_STORAGE_DATA = "INTENT_ACTION_DELETE_BATTERY_STORAGE_DATA";
	public static final String INTENT_ACTION_TOAST_DATA_SIZE = "ACTION_TOAST_DATA_SIZE";
	public static final String INTENT_ACTION_COPY_DATA_TO_SD = "INTENT_ACTION_COPY_DATA_TO_SD";
	
	private NotificationManager mNotificationManager;
    private final IBinder mBinder = new LocalBinder();
	private final int NOTIFICATION = 1;
	private BroadcastReceiver mBroadcastReceiverBatteryChange;
	private Settings powerSettings;
	private Date lastBatteryEventUnplug;
	private static final DateFormat DATEFORMAT_TIME_LAST_UNPLUGGED = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");
	private PendingIntent notificationClickedIntent;
	
	private TemporaryDataStorage dataStorage;
	private BatteryDao batteryDao;
	private DbLowPower dbLowPower;
	
	private BatteryData prevBatteryState;
	private final Integer batteryStateSync = 1;
	
	public class LocalBinder extends Binder{
		public PowerService getService(){
			return PowerService.this;
		}
	}
	
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
	
    @Override
    public void onCreate() {
    	mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
    	powerSettings = new Settings();
    	
    	notificationClickedIntent = PendingIntent.getActivity(
				getApplicationContext(), 0, 
				new Intent(getApplicationContext(), Launch.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), 
				Notification.FLAG_NO_CLEAR);
    	
    	// Display a notification about us starting.  We put an icon in the status bar.
    	startForeground(NOTIFICATION, buildNotification((String) getText(R.string.service_description_start), true));
    	
        // register receivers
        registerReceivers();
        
        batteryDao = getBatteryDao();
    }
    
    private BatteryDao getBatteryDao()
    {
    	dbLowPower = new DbLowPower(this);
    	BatteryDao dao = new BatteryDaoImpl(dbLowPower);

    	return dao;
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    	super.onStartCommand(intent, flags, startId);
    	performAnyContainedAction(intent);
        return START_STICKY;
    }

    private void performAnyContainedAction(Intent intentLaunch) {
    	String action = intentLaunch.getAction();
    	if (action == null) return;
    	
    	if (action.equals(INTENT_ACTION_LAST_UNPLUG_EVENT_STORE)) {
    		powerSettings.setLogLastUnplugged(true);
    	} else if (action.equals(INTENT_ACTION_LAST_UNPLUG_EVENT_IGNORE)) {
    		powerSettings.setLogLastUnplugged(false);
    	} else if (action.equals(INTENT_ACTION_TOAST_DATA_SIZE)) {
    		Toast.makeText(this, "persisted data size: " + dataStorage.getPersistedDataSize(this), Toast.LENGTH_SHORT).show();
    	} else if (action.equals(INTENT_ACTION_DELETE_BATTERY_STORAGE_DATA)) {
    		//dataStorage.wipeBatteryStoredData(this);
    	} else if (intentLaunch.getAction().equals(INTENT_ACTION_COPY_DATA_TO_SD)) {
    		saveBatteryToFile();
    	}
	}

	@Override
    public void onDestroy() {
        // Cancel the persistent notification.
        mNotificationManager.cancel(NOTIFICATION);
        unRegisterReceivers();
        // TODO: Close the DB here
    }

	private void registerReceivers() {
    	mBroadcastReceiverBatteryChange = new BroadcastReceiver() {
			@Override
			public void onReceive(Context context, Intent intent){
				int flagsToUse = UtilBatteryInterpreter.FLAG_REPORT_LEVEL 
									| UtilBatteryInterpreter.FLAG_REPORT_TEMPERATURE;
				StringBuffer updateMessage = new StringBuffer()
					.append(UtilBatteryInterpreter.getBatteryData(intent, flagsToUse));	
				
				if (powerSettings.isLogLastUnplugged()) {
					updateMessage.append("Last unplugged: ");
					boolean isPhoneCharging = UtilBatteryInterpreter.getPhoneCharging(intent);
					
					if (!isPhoneCharging && lastBatteryEventUnplug == null) {
						lastBatteryEventUnplug = new Date();	
					}
						
					if (isPhoneCharging) {
						updateMessage.append("charging");
						lastBatteryEventUnplug = null;
					
					} else {
						updateMessage.append(DATEFORMAT_TIME_LAST_UNPLUGGED.format(lastBatteryEventUnplug));						
					}
				}
				AppSettings.log(this.getClass(), "servicelog", "battery reciever triggered. ");
				updateNotification(updateMessage.toString());	
				
				// TODO: Here we cannot do much about a persistence exception so just log the error to our log
				AppSettings.log(this.getClass(), "servicelog", "Saving battery info");
				addBatteryStateIfDiff(createBattery(intent), prevBatteryState);
			}
		};
		IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
		registerReceiver(mBroadcastReceiverBatteryChange, filter);
	}
	
	/**
	 * If the battery state has changed in a way that we are interested in, then persist the new state to the database.
	 * @param newState
	 * @param oldState
	 */
	private void addBatteryStateIfDiff(BatteryData newState, BatteryData oldState)
	{
		// cannot sync on the oldState as it will be null on the first run
		synchronized(batteryStateSync)
		{
			if (!newState.equals(oldState))
			{
				batteryDao.insert(newState);
				prevBatteryState = newState;
			}
		}
	}
	
	private BatteryData createBattery(Intent intent)
	{
		return BatteryDataFactory.build(intent);
	}
	
	// TODO: Move this to getting triggered by a button
	// TODO: This is not thread safe should another battery change message arrive
	private void saveBatteryToFile()
	{
		new Thread(backgroundCopy).start();
	}
	
	/**
	 * this runnable is used to copy the data into a storage file on the SD
	 * This is used to start a new thread to put this into the background. 
	 */
	private Runnable backgroundCopy = new Runnable() {
		@Override
		public void run() {
			DbToFileAdapter backup = new DbToFileAdapter(dbLowPower.getReadableDatabase());
			try
			{
				backup.writeToFile("batteryinfo", "batteryinfo_dump.txt");
			} catch (IOException e)
			{
				AppSettings.log(this.getClass(), "saveBatteryToFile", e.getMessage());
			}
		}
		
	};
    
    private void unRegisterReceivers() {
    	if (mBroadcastReceiverBatteryChange != null) {
    		unregisterReceiver(mBroadcastReceiverBatteryChange);
    	}
    }
    
    /**
     * Update the notification with new text. 
     * @param text
     */
    private void updateNotification(String text) {
        mNotificationManager.notify(NOTIFICATION, buildNotification(text, false));
    }
    
    public Notification buildNotification(String text, boolean setTicker) {
    	String tickerText = setTicker ? text : null;
    	Notification notification = new Notification(R.drawable.ic_launcher, tickerText, System.currentTimeMillis());
		RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification);
		contentView.setImageViewResource(R.id.image, R.drawable.ic_launcher);
		contentView.setTextViewText(R.id.text, text);
		notification.contentView = contentView;
		notification.contentIntent = notificationClickedIntent;
		return notification;
    }
    
    /**
     * Helper method for getting an intent to launch this service
     * @param context
     * @return
     */
    public static Intent getLaunchIntent (Context context) {
    	return new Intent(context, PowerService.class);
    }

    /**
     * Helper method for getting an intent to launch this service with an action. 
     * @param context
     * @param intentActionDeleteBatteryStorageData
     * @return
     */
	public static Intent getLaunchIntentWithAction(Context context, String intentActionDeleteBatteryStorageData) {
		Intent intent = new Intent(context, PowerService.class);
		intent.setAction(intentActionDeleteBatteryStorageData);
		return intent;
	}
    
}